/*
 * tcp_connection.cpp
 *
 *  Created on: 2016-4-2
 *      Author: ZhangXiyin
 */

#include "tcp_connection.h"
#include "tcp_socket.h"
#include "../../base/packet_factory_base.h"
#include "../../base/connection_handler_base.hpp"
#include "../../base/packet_base.hpp"

#include <boost/asio/placeholders.hpp>

namespace eyas {
namespace io {

tcp_connection::tcp_connection(tcp_socket_ptr tcp_skt_ptr)
:tcp_skt_ptr_(tcp_skt_ptr)
, io_service_(tcp_skt_ptr_->get_ioservice()), socket_(tcp_skt_ptr_->get_socket()), endpoint_(tcp_skt_ptr_->get_endpoint())
, wait_recv_len_(0), disable_(false){
}

tcp_connection::~tcp_connection() {
	this->close();
}

void tcp_connection::close(){
	boost::recursive_mutex::scoped_lock lck(this->mutex_);
	this->disable_ = true;
	this->socket_.close();
}

void tcp_connection::handle_write(eyas::buffer::iobuffer_slices_ptr& slicesPtr, const boost::system::error_code& error, size_t bytes_transferred) {
	if(error){
		return this->do_error(error);
	}
}
void tcp_connection::handle_read(eyas::buffer::iobuffer_slices_ptr& bufferSlicesPtr, const boost::system::error_code& error, size_t bytes_transferred){
	if(error){
		return this->do_error(error);
	}
	if(bytes_transferred > 0){
		wait_recv_len_ -= bytes_transferred;
		bufferSlicesPtr->commit_write((int32_t)bytes_transferred);
		this->read_buffer_.commit_write((int32_t)bytes_transferred);
		if(wait_recv_len_ <= 0){
			if(this->pkt_decoder_ptr_->decode(this->read_buffer_)){
				// 解析完成
				if(nullptr != this->dat_handler_ptr_){
					this->dat_handler_ptr_->on_data_received(this->pkt_decoder_ptr_->data(), error);
				}
			}
		}
	}
	ready_for_next_read();
}
void tcp_connection::do_error(const boost::system::error_code& error){
	{
		boost::recursive_mutex::scoped_lock lck(this->mutex_);
		if(this->disable_){
			return;
		}
		this->disable_ = true;
		this->socket_.close();
	}
//	if(nullptr != this->conn_handler_ptr_){
//		this->conn_handler_ptr_->on_closed(this->shared_from_this(), error);
//	}
	return;
}

void tcp_connection::ready_for_next_read(){
	if(wait_recv_len_ <= 0){
		wait_recv_len_ = this->pkt_decoder_ptr_->advance_recv_buffer();
	}
	eyas::buffer::iobuffer_slices_ptr bufferSlicesPtr = read_buffer_.get_write_buffer();
	int32_t idleLength = bufferSlicesPtr->idlelength();
	unsigned char* writeBuffer = bufferSlicesPtr->get_write_buffer();
	this->socket_.async_read_some(boost::asio::buffer(writeBuffer, idleLength > wait_recv_len_ ? wait_recv_len_ : idleLength),
			boost::bind(&tcp_connection::handle_read,
					this->shared_from_this(),
					bufferSlicesPtr,
					boost::asio::placeholders::error,
					boost::asio::placeholders::bytes_transferred));
}

void tcp_connection::write(packet_encoder_base& packet){
	// 此处无需担心性能，已在iobuffer内做了内存优化，已启用内存重利用机制
	eyas::buffer::iobuffer writeBuffer;
	packet.encode(writeBuffer);
	eyas::buffer::iobuffer_slices_ptr slicesPtr;
	boost::recursive_mutex::scoped_lock lck(this->mutex_);
	if(this->disable_){
		return;
	}
	while(nullptr != (slicesPtr = writeBuffer.pop())){
		this->socket_.async_send(
			boost::asio::buffer(slicesPtr->get_read_buffer(), slicesPtr->length()),
				boost::bind(&tcp_connection::handle_write,
					shared_from_this(),
					slicesPtr,
					boost::asio::placeholders::error,
					boost::asio::placeholders::bytes_transferred));
	}
}

} /* namespace thread */
} /* namespace eyas */
